package cn.shadow.game.chess.CHnchess.chessman;

import cn.shadow.game.chess.CHnchess.board.*;
import cn.shadow.game.chess.CHnchess.type.Camp;
import cn.shadow.game.chess.CHnchess.type.ChessType;
import cn.shadow.proto.client.CHnChessClientProtoContent;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


/**
 * 抽象的棋子类,保存了棋子的基本信息
 */
public abstract class AbstractChess implements Chess, Route {
    /**
     * 可以走的点
     */
    protected List<Position> canSetPosition = new ArrayList<>();

    /**
     * 可以攻击的点
     */
    protected List<Position> canAttackPosition = new ArrayList<>();
    /**
     * 保存了整个棋盘的对象,一定存在
     */
    protected Board board;
    /**
     * 棋子类型
     */
    protected ChessType type;

    /**
     * 所属阵营
     */
    protected Camp camp;

    /**
     * 当前所在的位置
     */
    protected Position position;

    /**
     * 选中
     */
    private boolean chosen;

    public AbstractChess(ChessType type, Board board, Camp camp) {
        this.board = board;
        this.type = type;
        this.camp = camp;
    }

    public Board getBoard() {
        return board;
    }

    public ChessType getType() {
        return type;
    }

    public void setType(ChessType type) {
        this.type = type;
    }

    public void setCamp(Camp camp) {
        this.camp = camp;
    }

    @Override
    public Position getPosition() {
        return position;
    }

    @Override
    public void setPosition(Position position) {
        this.position = position;
    }

    @Override
    public boolean isChosen() {
        return chosen;
    }

    public void setChosen(boolean chosen) {
        this.chosen = chosen;
    }

    @Override
    public Camp getCamp() {
        return camp;
    }


    @Override
    public String toString() {
        return getType().getName() + ":" + getCamp() + ":" + getPosition();
    }

    /**
     * @return 返回可以走的位置
     */
    @Override
    public List<Position> getCanSetPosition() {
        addAllPoint();
        List<Position> points = new ArrayList<>(canSetPosition);
        canAttackPosition.clear();
        canSetPosition.clear();
        return points;
    }

    /**
     *
     * @return 可以攻击的位置
     */
    @Override
    public List<Position> getCanAttackPosition() {
        addAllPoint();
        List<Position> points = new ArrayList<>(canAttackPosition);
        canAttackPosition.clear();
        canSetPosition.clear();
        return points;
    }

    public void addAllPoint() {
        boolean betweenCommanders = betweenCommanders();
        if (this instanceof Line) {
            Line line = (Line) this;
            line.addDownPoint(); //向下
            line.addUpPoint();   //向上
            if (betweenCommanders) {
                return;
            }
            line.addRightPoint(); //向右
            line.addLeftPoint(); //向左
        } else if (this instanceof Slash) {
            if (betweenCommanders) {
                return;
            }
            Slash slash = (Slash) this;
            slash.addLeftUpPoint();
            slash.addRightUpPoint();
            slash.addLeftDownPoint();
            slash.addRightDownPoint();
        }
    }

    /**
     * 是否在两个将之间,如果在,则某些位置不能移动
     *
     * @return
     */
    public boolean betweenCommanders() {
        Position myJiang = null;
        Position enemyjiang = null;
        for (Position point : getBoard().getTable().values()) {
            Chess chess = point.getChess();
            if (chess != null && chess.getType() == ChessType.SHUAI) {
                if (chess.getCamp() == getCamp()) {
                    myJiang = chess.getPosition();
                } else {
                    enemyjiang = chess.getPosition();
                }
            }
        }
        assert myJiang != null;
        assert enemyjiang != null;
        if (myJiang.getCol() != enemyjiang.getCol() || getCol() != enemyjiang.getCol()) { //不在一条水平线上
            return false;
        }

        //获得两个位置,然后判断自己的位置是否刚好在中间

        int myjiangRow = myJiang.getRow();
        int enJiangRow = enemyjiang.getRow();
        int max = Math.max(myjiangRow, enJiangRow);
        int min = Math.min(myjiangRow, enJiangRow);
        int row = getRow();
        int col = getCol();

        for (int i = row + 1; i < max; i++) {
            Position point = getBoard().getPoint(i, col);
            if (point.getChess() != null) {
                return false;
            }
        }

        for (int i = row - 1; i > min; i--) {
            Position point = getBoard().getPoint(i, col);
            if (point.getChess() != null) { //中间有一个棋子
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        AbstractChess that = (AbstractChess) o;
        return Objects.equals(board, that.board) &&
                type == that.type &&
                camp == that.camp &&
                Objects.equals(position, that.position);
    }

    @Override
    public int hashCode() {
        return Objects.hash(board, type, camp, position);
    }

    public boolean isBlack() {
        return getCamp() == Camp.BLACK;
    }

    @Override
    public int getCol() {
        return position.getCol();
    }

    @Override
    public int getRow() {
        return position.getRow();
    }

    @Override
    public Chess copy(ChessType type, Board board, Camp camp) {
        return ChessFactory.createChess(board, camp, type);
    }

    @Override
    public CHnChessClientProtoContent.ChessMsg chessMsg() {
        CHnChessClientProtoContent.ChessMsg.Builder chess = CHnChessClientProtoContent.ChessMsg.newBuilder();
        chess.setChessCamp(this.camp.getValue());
        chess.setChessType(this.type.value());
        return chess.build();
    }
}
